import {
  DIRECTION_LEFT,
  DIRECTION_RIGHT,
  DIRECTION_UP,
  DIRECTION_DOWN
} from '../util/const'
import { ease } from '../util/ease'

export function snapMixin (GScroll) {
  GScroll.prototype._initSnap = function () {
    let snap = this.options.snap
    let stepX = snap.stepX || this.wrapper.offsetWidth
    let stepY = snap.stepY || this.wrapper.offsetHeight
    if (snap.loop) {
      let scrollerLen = this.scroller.children.length
      let firstChild = this.scroller.children[0]
      let lastChild = this.scroller.children[scrollerLen - 1]
      this.scroller.insertBefore(lastChild.cloneNode(true), firstChild)
      this.scroller.appendChild(firstChild.cloneNode(true), lastChild)
    }
    setTimeout(() => {
      this.refresh()
      if (snap.loop) {
        this.hasHorizontalScroll && this.scrollTo(-stepX, 0, 0)
        this.hasVerticalScroll && this.scrollTo(0, -stepY, 0)
        this.currentPage = 1
      } else {
        this.currentPage = 0
      }
    }, 100)
    this.on('refresh', () => {
      let index = 0
      this.page = []
      let stepX = snap.stepX || this.wrapperWidth
      let stepY = snap.stepY || this.wrapperHeight
      let scrollerLen = this.scroller.children.length
      for (let i = 0; i < scrollerLen; i++) {
        this.page[i] = {}
        if (this.hasHorizontalScroll) {
          this.page[i][index] = {
            cx: -stepX / 2 - stepX * i,
            cy: 0,
            x: -stepX * i,
            y: 0
          }
          this.scroller.children[i].style.width = stepX + 'px'
        }
        if (this.hasVerticalScroll) {
          this.page[i][index] = {
            cx: 0,
            cy: -stepY / 2 - stepY * i,
            x: 0,
            y: -stepY * i
          }
          this.scroller.children[i].style.height = stepY + 'px'
        }
      }
      this.hasHorizontalScroll && (this.scroller.style.width = stepX * scrollerLen + 'px')
      this.hasVerticalScroll && (this.scroller.style.height = stepY * scrollerLen + 'px')
    })
    this.on('scrollEnd', () => {
      clearTimeout(this.scrollEndSnapTimer)
      this.scrollEndSnapTimer = setTimeout(() => {
        if (snap.loop) {
          if (this.currentPage === 0) {
            this.currentPage = this.page.length - 2
            this.hasHorizontalScroll && (this.scrollTo(-stepX * (this.currentPage), 0, 0))
            this.hasVerticalScroll && (this.scrollTo(0, -stepY * (this.currentPage), 0))
          }
          if (this.currentPage > this.page.length - 2) {
            this.currentPage = 1
            this.hasHorizontalScroll && (this.scrollTo(-stepX * (this.currentPage), 0, 0))
            this.hasVerticalScroll && (this.scrollTo(0, -stepY * (this.currentPage), 0))
          }
        }
        this.enable()
      }, snap.speed - 100)
    })
  }

  GScroll.prototype._nearestSnap = function (distX, distY) {
    this.disable()
    let snap = this.options.snap
    let threshold = snap.threshold
    let currentPage = {}
    let pageNum = this.currentPage
    this.page.forEach((v, i) => {
      if (i === pageNum) {
        if (Math.abs(distX - this.page[i][0].x) > threshold) {
          this.directionX === DIRECTION_LEFT && (currentPage = this._snapBound(snap, i, 'x', DIRECTION_LEFT))
          this.directionX === DIRECTION_RIGHT && (currentPage = this._snapBound(snap, i, 'x', DIRECTION_RIGHT))
          return
        }
        if (Math.abs(distY - this.page[i][0].y) > threshold) {
          this.directionY === DIRECTION_UP && (currentPage = this._snapBound(snap, i, 'y', DIRECTION_UP))
          this.directionY === DIRECTION_DOWN && (currentPage = this._snapBound(snap, i, 'y', DIRECTION_DOWN))
          return
        }
        currentPage = this.page[i][0]
        this.enable()
      }
    })
    if (Object.keys(currentPage).length === 0) {
      currentPage = this.page[pageNum][0]
    }
    return currentPage
  }

  GScroll.prototype._snapBound = function (snap, i, axis, direction) {
    if (!axis && !direction) {
      return ''
    }
    let page = {}
    if ((axis === 'x' && direction === DIRECTION_LEFT) ||
       (axis === 'y' && direction === DIRECTION_UP)) {
      if (!snap.loop) {
        if (this.currentPage === this.page.length - 1) {
          page = this.page[i][0]
          return
        }
      }
      page = this.page[i + 1][0]
      this.currentPage++
    }
    if ((axis === 'x' && direction === DIRECTION_RIGHT) ||
       (axis === 'y' && direction === DIRECTION_DOWN)) {
      if (!snap.loop) {
        if (this.currentPage === 0) {
          page = this.page[i][0]
          return
        }
      }
      page = this.page[i - 1][0]
      this.currentPage--
    }
    return page
  }

  GScroll.prototype.goNext = function () {
    let pageNum = this.currentPage++
    this.goToPage(pageNum, 'next')
  }

  GScroll.prototype.goPrev = function () {
    let pageNum = this.currentPage--
    this.goToPage(pageNum, 'prev')
  }

  GScroll.prototype.goToPage = function (pageNum, direct) {
    let snap = {}
    direct === 'next' && (snap = this.page[pageNum + 1][0])
    direct === 'prev' && (snap = this.page[pageNum - 1][0])
    let newX = snap.x
    let newY = snap.y
    let easing = ease.swipeBounce
    let time = 300
    this.scrollTo(newX, newY, time, easing)
  }

  GScroll.prototype.getCurrentPage = function () {
    return this.currentPage
  }
}
